#include "Player.h"
#include <daisy\OgreGraphicsManager.h>
#include <daisy\EventSystem.h>
#include <daisy\System.h>
#include <OGRE\Ogre.h>
#include <daisy\NewtonPhysicsManager.h>
#include "ModelConfig.h"
#include <Branch1EventDef.h>
#include <daisy\FmodSoundManager.h>
#pragma warning(disable:4305)
using namespace DAISY;
Player::Player(const std::string &name):
MovableObject(name),
//wmgr(CEGUI::WindowManager::getSingleton()),
isForward(false), 
isBack(false),
isLeft(false),
isRight(false),
isSightUp(false),
_velocity(20.0f),
_originalVel(20.0f),
_turbVel(100),
forwardSpeed(0.0f),
sideSpeed(0.0f),
isMove(0),
isRotate(0),
isSightDown(false),
isSightLeft(false),
isSightRight(false),
rot_sig_lim(45.0f),
curr_rot_sig(0.0f)
{
	//CEGUI::SchemeManager::getSingleton().create("TaharezLook.scheme");
}
Player::~Player(){}
void Player::doEnable()
{
	/*_timeLine = 0;*/
	using namespace Ogre;
	_sceneMgr = DAISY::OgreGraphicsManager::getInstance().getSceneManager();

	_camera = _sceneMgr->createCamera("MainCamera");
	DAISY::OgreGraphicsManager::getInstance().getRenderWindow()->getViewport(0)->setCamera(_camera);
	DAISY::OgreNewtManager::getInstance().setPhysicsSpeed(1.5);
	
	
	//enable update 
	enableUpdate(true);
	setChannel(DAISY::EventChannel::create().addUserChannel<1>());
	listening(getChannel());

	OgreNewt::World* m_World = DAISY::OgreNewtManager::getInstance().getNewtWorld();

	m_World->setWorldSize(Ogre::AxisAlignedBox(-20000,-20000,-20000,20000,20000,20000));
	
	OgreNewt::CollisionPtr col;
	//Ogre::Vector3 size;
	//size = Ogre::Vector3( 1, 1, 1 );
	_node = _sceneMgr->getRootSceneNode()->createChildSceneNode("robot",Ogre::Vector3(4541.97,20,6833.6));
	_entity = _sceneMgr->createEntity("robot", "robot.mesh" );
	//_entity->setMaterialName("Examples/CelShadingTextured");
	_node->attachObject( _entity );
	//_node->setScale( size );
	_oriCamPit = Vector3(-50,80,-110);
	_oriSigPit = Vector3(-50,45,100);
	_sigRadius = _oriSigPit.length();
	_sightNode = _node->createChildSceneNode("robot_sight",_oriSigPit);
	_cameraNode = _node->createChildSceneNode("robot_camera",_oriCamPit);
	
	ExtendedCamera* exCamera = new ExtendedCamera("exCanera",_sceneMgr,_camera);
	_cameraMan = new SdkCameraMan(_node,_sightNode,_cameraNode);
	_cameraMan->setExCamera(exCamera);
	_cameraMan->setStyle(SdkCameraMan::CS_3RDCHASE);



	_animState = _entity->getAnimationState("Idle"); 
	_animState->setLoop(true); 
	_animState->setEnabled(true);

	/*_node_player = node->createChildSceneNode("cameraP1",Ogre::Vector3(0,15,0));
	_node_player->lookAt(Ogre::Vector3(0,0,0),Ogre::Node::TransformSpace::TS_PARENT);*/
	
	
	/*m_World->getDebugger().showDebugInformation();*/
	
	// rigid body. 
	OgreNewt::CollisionPrimitives::ConvexHull *boxcol = new OgreNewt::CollisionPrimitives::ConvexHull(m_World, _entity, 1);//at the last moment of the collsion between terrain and outr chracter,buffer overflow happen when use convexHull collsion
	col.reset(boxcol); 
	bod = new OgreNewt::Body( m_World, col );
	bod->attachNode( _node ); 
	// initial position 
	bod->setPositionOrientation(Ogre::Vector3(4541.97,20,6833.6) ,Ogre::Quaternion::IDENTITY );
	Ogre::Real mass = 20.0;
	Ogre::Vector3 inertia, centerOfMass;
	boxcol->calculateInertialMatrix(inertia, centerOfMass); 
	inertia*=mass; 
	bod->setMassMatrix( mass, inertia );
	bod->setCenterOfMass(centerOfMass);
	// body->setCustomForceAndTorqueCallback <Player>(&Player::setCustomForceCallback,this);
	bod->setStandardForceCallback();
	//delete boxcol;
	
	_newtPlayer  = new OgreNewt::PlayerController(bod, 0.4f);
	//CEGUI::Window *sheet = wmgr.createWindow("DefaultWindow", "CEGUIDemo/Sheet");
	//CEGUI::Window *info = wmgr.createWindow("TaharezLook/Button", "Info");
	//
	//info->setText("Info");
	//info->setSize(CEGUI::UVector2(CEGUI::UDim(0.50, 50), CEGUI::UDim(0.1, 10)));
	//info->setAlpha(0);

	//CEGUI::Window* st = wmgr.createWindow("TaharezLook/StaticText", "panel");
	//sheet->addChildWindow(st);
	//st->setPosition(CEGUI::UVector2(cegui_reldim(0.25f), cegui_reldim( 0.5f)));
	//st->setSize(CEGUI::UVector2(cegui_reldim(0.96f), cegui_reldim( 0.25f)));
	//st->setText("Demo -this is a game about life, and soul");


 //


	//st->setProperty("FrameEnabled", "false");
	//st->setProperty("BackgroundEnabled", "false");

 //

	///*sheet->addChildWindow(info); */
	//CEGUI::System::getSingleton().setGUISheet(sheet);
	///*info->subscribeEvent(CEGUI::PushButton::EventKeyDown, CEGUI::Event::Subscriber(&Player::showinfo, this));*/

	
	



	//regist input

	_sound_collision = DAISY::FmodSoundManager::getInstance().createPlayer("test.wav");
	_sound_collision->setVolume(100);
	_sound_collision->load();
	
	DAISY::OISInputManager::getSingleton().addKeyListener(this);

}
void Player::doDisable()
{
	DAISY::OgreNewtManager::getInstance().getNewtWorld()->destroyAllBodies();
}
void Player::doFrame()
{
	/*_timeLine += SystemInterface::getInstance().getInterval();*/
	/*_cameraMan->frameRenderingQueued(_interval);*/
	//doKeyFrame();
	/*showinfo();*/
	// TODO CHANGE expression of judgement
	Real timestep = SystemInterface::getInstance().getInterval();
	Real rate = 30.0f;
	Ogre::Vector3 tempPosition;
	Ogre::Quaternion tempQuat;
	Ogre::Node* tempNode = bod->getOgreNode();                           //can directly modify quaternion
	tempNode->yaw(Ogre::Radian(Ogre::Degree(sideSpeed*timestep*rate)));
	bod->getPositionOrientation(tempPosition,tempQuat);
	bod->setPositionOrientation(tempPosition,tempNode->getOrientation());
	
	//heading = Ogre::Radian(yawDir);
	_newtPlayer->setVelocity(forwardSpeed, 0, tempNode->getOrientation().getYaw());
	
	if(_robotAniState == IDLE)
	{
		_animState = _entity->getAnimationState("Idle"); 
		
	}
	else if(_robotAniState == WALK)
	{
		_animState = _entity->getAnimationState("Walk"); 
		
	}
	_animState->setLoop(true); 
	_animState->setEnabled(true);

	if(isRotate > 0)
	{
		
		rate =50.0f *timestep*rate;
		curr_rot_sig+=rate;
		if(isSightUp)
		{
			_sightNode->setPosition(0,0,0);
			Ogre::Quaternion qu;
			//qu.FromAngleAxis(Ogre::Radian(),_node->getOrientation().get
			_sightNode->pitch(Ogre::Radian(Ogre::Degree(-rate)));
			_sightNode->translate(_oriSigPit,Ogre::Node::TS_LOCAL);
		}
		if(isSightDown)
		{
			_sightNode->setPosition(0,0,0);
			_sightNode->pitch(Ogre::Radian(Ogre::Degree(rate)));
			_sightNode->translate(_oriSigPit,Ogre::Node::TS_LOCAL);
		}
		if(isSightLeft)
		{
			_sightNode->setPosition(0,0,0);
			_sightNode->yaw(Ogre::Radian(Ogre::Degree(rate)));
			_sightNode->translate(_oriSigPit,Ogre::Node::TS_LOCAL);
		}
		if(isSightRight)
		{
			_sightNode->setPosition(0,0,0);
			_sightNode->yaw(Ogre::Radian(Ogre::Degree(-rate)));
			_sightNode->translate(_oriSigPit,Ogre::Node::TS_LOCAL);
		}

		
	}
	_cameraMan->frameRenderingQueued(timestep);
	_animState->addTime(timestep*_velocity);
	if((_node->_getDerivedPosition()-minDistance()).length() <= 200)
	{
		bod->removeForceAndTorqueCallback();
		bod->setStandardForceCallback();
		_sound_collision->play();
	}

}
void Player::doExecute(DAISY::Event * evt)
{
	if(DAISY::BRANCH1Events::equal(evt,DAISY::BRANCH1Events::AIMING))
	{
		if(evt->getSender().get() != shared_from_this().get() )
		{
		Ogre::Vector3 danPosit = evt->getData<Ogre::Vector3>();
		_posit_dandelions.push_back(danPosit);
		//_targetPosit = minDistance();
		Ogre::LogManager::getSingleton().logMessage("1: "+Ogre::StringConverter::toString(_node->_getDerivedPosition()-minDistance())+"2: "+Ogre::StringConverter::toString(minDistance()-(_node->_getDerivedOrientation() * _node->_getDerivedPosition())));

		}
	}

}


bool Player::onKeyPressed(const KeyEvent & evt)
{
	_cameraMan->injectKeyDown(evt);
	switch(evt.getKey())
	{
	case KC_R:
		_camera->setPosition(0,0,0);
		break;
	case KC_X:
		bod->setPositionOrientation(Ogre::Vector3(4541.97,2000,6833.6),Ogre::Quaternion::IDENTITY);
		break;
	case KC_F:
		bod->freeze();
		break;
	case KC_U:
		bod->unFreeze();
		break;
	case KC_W:
		isForward = true;
		isMove++;
		forwardSpeed -= _velocity;
		_robotAniState = WALK;
		break;
	case KC_S:
		isBack = true;
		isMove++;
		forwardSpeed += Ogre::Math::Abs(_velocity-5);
		_robotAniState = WALK;
		break;
	case KC_A:
		isLeft = true;
		isMove++;
		sideSpeed += 5.0;
		_robotAniState = WALK;
		break;
	case KC_D:
		isRight = true;
		isMove++;
		sideSpeed -= 5.0;
		_robotAniState = WALK;
		break;
	case KC_LSHIFT:
		_velocity = _turbVel;
		break;
	case KC_I:
		{
			isSightUp = true;
			isRotate++;
			_cameraMan->setTithness(1);
		}
		break;
	case KC_K:
		{
			isSightDown = true;
			isRotate++;
			_cameraMan->setTithness(1);
		}
		break;
	case KC_J:
		{
			isSightLeft = true;
			isRotate++;
			_cameraMan->setTithness(1);
		}
		break;
	case KC_L:
		{
			isSightRight = true;
			isRotate++;
			_cameraMan->setTithness(1);
		}
		break;
	case KC_Z:
		bod->removeForceAndTorqueCallback();
		bod->setStandardForceCallback();
		break;
	case KC_SPACE:
		{
			bod->removeForceAndTorqueCallback();
			bod->setCustomForceAndTorqueCallback <Player>(&Player::setCustomForceCallback,this);
		}
		break;
	case DAISY::KC_N:
		findTarget();
		break;
	case KC_M:
		Ogre::LogManager::getSingleton().logMessage("positon: "+Ogre::StringConverter::toString(_node->getPosition()));
		break;
	default:
		break;

	}		

	return true;
}
bool Player::onKeyReleased(const KeyEvent & evt)
{
	_cameraMan->injectKeyUp(evt);
	switch(evt.getKey())
	{
	case KC_W:
		isForward = false;
		forwardSpeed = 0;
		isMove--;
		if(!isMove)
		{
			_robotAniState = IDLE;
			isMove = false;
		}
		break;
	case KC_S:
		isBack = false;
		forwardSpeed = 0;
		isMove--;
		if(!isMove)
		{
			_robotAniState = IDLE;
			isMove = false;
		}
		break;
	case KC_A:
		isLeft = false;
		sideSpeed = 0;
		isMove--;
		if(!isMove)
		{
			_robotAniState = IDLE;
			isMove = false;
		}
		break;
	case KC_D:
		isRight = false;
		sideSpeed = 0;
		isMove--;
		if(!isMove)
		{
			_robotAniState = IDLE;
			isMove = false;
		}
		break;
	case KC_LSHIFT:
		_velocity = _originalVel;
		break;
	case KC_I:
		{
			isSightUp = false;
			isRotate--;
			_cameraMan->setTithness(0.1);
		}
		break;
	case KC_K:
		{
			isSightDown = false;
			isRotate--;
			_cameraMan->setTithness(0.1);
		}
		break;
	case KC_J:
		{
			isSightLeft = false;
			isRotate--;
			_cameraMan->setTithness(0.1);
		}
		break;
	case KC_L:
		{
			isSightRight = false;
			isRotate--;
			_cameraMan->setTithness(0.1);
		}
		break;
	default:
		break;

	}
	return true;
}
//void Player::doKeyFrame()
//{
//	std::map<float, mfun>::iterator it;
//	for(it = _mapFun.begin();it!= _mapFun.end();)
//	{
//		float temp = it->first - _timeLine;
//		if(temp<=0.03&&temp>=-0.03)
//		{
//			(this->*_mapFun[it->first])();
//			_mapFun.erase(it++);
//		}
//		else if(it->first <= _timeLine)
//		{
//			(this->*_mapFun[it->first])();
//			_mapFun.erase(it++);
//		}
//		else
//		{
//			it++;
//		}
//	}
//}
//void Player::keyFrame0()
//{
//	_cameraPtr->setPosition(4706.42, 59.5326, 1124.83);
//	_cameraPtr->setOrientation(Ogre::Quaternion(0.473801, 0.0989653, -0.856455, 0.17953));
//	CEGUI::Window* st = wmgr.getWindow("panel");
//	st->setText("\" You must take it to us\"");
//
//}
//void Player::keyFrame1()
//{
//	_cameraPtr->setPosition(5171.67, 761.446, 2991.55);
//	_cameraPtr->setOrientation(Ogre::Quaternion(-0.688438, -0.617635, 0.282831, -0.254233));
//}
//void Player::keyFrame2()
//{
//	/*_cameraPtr->setPosition(3937.98, 664.306 ,4068.59);
//	_cameraPtr->setOrientation(Ogre::Quaternion(0.00893741, 0.00202197, -0.974164, 0.225808));*/
//	CEGUI::Window* st = wmgr.getWindow("panel");
//	st->setText("\"so,you can be the hero for humanbeing\"");
//}
//void Player::keyFrame3()
//{
//	/*bod->setPositionOrientation(Ogre::Vector3(4000, 1441.1, 4000),Ogre::Quaternion::IDENTITY);
//	_cameraPtr->setPosition(4046.02, 1485.06, 3945 );
//	_cameraPtr->setOrientation(Ogre::Quaternion(0.148574, 0.00685432, 0.988116, -0.0435983));*/
//	CEGUI::Window* st = wmgr.getWindow("panel");
//	st->setText("\"like the sun,rising for people\"");
//
//}
//void Player::keyFrame4()
//{
//	_cameraPtr->setPosition(Ogre::Vector3(5171.67, 761.446, 2991.55));
//	_cameraPtr->setOrientation(Ogre::Quaternion(-0.688438, -0.617635, 0.282831, -0.254233));
//	_cameraPtr->setAutoTracking(true,_sceneMgr->getSceneNode("robot"));
//	
//	
//	bod->setPositionOrientation(Ogre::Vector3(4541.97,2000,6833.6),Ogre::Quaternion::IDENTITY);
//	CEGUI::Window* st = wmgr.getWindow("panel");
//	st->setText("So,I'm here,for that");
//	/*_cameraPtr->setPosition( 4043.11, 1770.21, 3972.25);
//	_cameraPtr->setOrientation(Ogre::Quaternion(0.20627, 0.0980426, 0.880002, -0.416504));*/
//
//}
//
//void Player::keyFrame5()
//{
//	//_cameraPtr->setAutoTracking(false);
//	_cameraPtr->setPosition(Ogre::Vector3(4517.86, 1596.93, 6456.81));
//	_cameraPtr->setOrientation(Ogre::Quaternion(-0.0317675, -0.00335771, 0.993953, -0.105057));
//}
//void Player::keyFrame6()
//{
//	//_cameraPtr->setAutoTracking(false);
//	_cameraPtr->setPosition(Ogre::Vector3(4520.88, 1639.27, 7187));
//	_cameraPtr->setOrientation(Ogre::Quaternion(0.998107, 0.0538394, -0.0297, 0.00160206));
//}
//void Player::keyFrame7()
//{
//	//_cameraPtr->setAutoTracking(false);
//	_cameraPtr->setPosition(Ogre::Vector3(4680.29, 1525.54, 6833.2));
//	_cameraPtr->setOrientation(Ogre::Quaternion(0.645752, 0.285609, 0.647604, -0.286428));
//}
//void Player::keyFrame8()
//{
//	_cameraPtr->setPosition(Ogre::Vector3(4596.82 ,29.4792, 6730.6));
//	_cameraPtr->setOrientation(Ogre::Quaternion(-0.239401, -0.0054884, -0.970703, 0.0221971));
//
//}
//void Player::keyFrame9()
//{
//	_cameraPtr->setAutoTracking(false);
//	//_sceneMgr->setShadowTechnique(Ogre::SHADOWDETAILTYPE_STENCIL);
//	CEGUI::Window* st = wmgr.getWindow("panel");
//	st->setPosition(CEGUI::UVector2(cegui_reldim(0.75f), cegui_reldim( 0.0f)));
//	st->setText("To be continued");
//}
//void Player::keyFrame10()
//{
//	_cameraPtr->setPosition(Ogre::Vector3(5082.04, 140.308, 5648.04));
//	_cameraPtr->setOrientation(Ogre::Quaternion(-0.258805, -0.00447785, -0.965894, 0.0164571));
//}
//void Player::showinfo()
//{
//	CEGUI::Window * info = wmgr.getWindow("Info");
//	Ogre::Vector3 tempv;
//	Ogre::Quaternion tempq;
//	bod->getPositionOrientation(tempv,tempq);
//	info->setText("timeline:"+Ogre::StringConverter::toString(_timeLine)/*+"cp:"+Ogre::StringConverter::toString(_cameraPtr->getPosition())+"co:"+Ogre::StringConverter::toString(_cameraPtr->getOrientation())+"hp:"+Ogre::StringConverter::toString(tempv)+Ogre::StringConverter::toString(_sceneMgr->getSceneNode("robot")->getPosition())*/);
//}
void Player::setCustomForceCallback(OgreNewt::Body* me, float timestep, int threadindex)
{
	Ogre::Real mass;
	Ogre::Vector3 inertia;

	me->getMassMatrix( mass, inertia );

	Ogre::Vector3 gravity = Ogre::Vector3(0,-9.8,0) * mass;
	me->addForce(mass*(minDistance()-_node->_getDerivedPosition()));
	me->addForce(gravity);

}
const std::string & Branch1PlayerFactory::getTypeName() const
{
	static const std::string typeName("Player");	
	return typeName;
}
Branch1PlayerFactory::pointer_type Branch1PlayerFactory::createInstance(const std::string& instanceName, parameter_type parameter)
{
	return pointer_type(new Player(instanceName)); 
}
void Player::findTarget()
{
	DAISY::Event* evt = DAISY::EventFactory::getInstance().createEvent();
	evt->setSender(shared_from_this());
	evt->setMsg(DAISY::BRANCH1Events::AIMING);
	//evt->setData<Ogre::Vector3>(_node->_getDerivedPosition());
	getEventManager()->broadcasting(evt);
	//TODO
}
std::string& Player::decode(const CEGUI::String& str)
{
	char sdes[2048];
	static std::string result;
	int len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);
	wchar_t* wcstr = new wchar_t[len];
	MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, wcstr, len);

	int wlen = WideCharToMultiByte(CP_ACP, 0, wcstr, -1, NULL, 0, NULL, NULL);
	char* nstr = new char[wlen];
	WideCharToMultiByte(CP_ACP, 0, wcstr, -1, nstr, wlen, NULL, NULL);

	strcpy(sdes, nstr);

	delete[] wcstr;
	delete[] nstr;

	result = sdes;

	return result;
}
Ogre::Vector3 Player::minDistance()
{
	if(_posit_dandelions.size()>0)
	{
		Ogre::Vector3 min = _posit_dandelions[0];
		for(int i = 0;i<_posit_dandelions.size();i++)
		{
			if(_posit_dandelions[i]< min)
			{
				min = _posit_dandelions[i];
			}
		}
		return min;
	}
	else
		return Ogre::Vector3(0,0,0);

}